local oo = require("SharedLibs.BaseLib")
local co = require("SharedLibs.CoroLib")

Debugger = require("SharedLibs.Debugger")
SyncOp = require("SharedLibs.Ops.SyncOp")

TU = require("SharedLibs.Utils.TableUtil")

WaitSignal = require("SharedLibs.Signal.WaitSignal")
Signal2PropMapper = require("SharedLibs.Signal.Signal2PropMapper")

Property = require("SharedLibs.Signal.Property")
TupleProperty = require("SharedLibs.Signal.TupleProperty")
Mapper1 = require("SharedLibs.Signal.PropertyMapper")
Mapper2 = require("SharedLibs.Signal.PropertyMapper2")
MapperN = require("SharedLibs.Signal.PropertyMapperN")

---
local m = {}

function m.Extend1(cls)
	---[Static] 从一个Signal来构造一个Property
	--- Signal触发直接导致Property变化.
	function cls.FromSignal(signal, initValue, name)
		local property = Signal2PropMapper.new(signal, initValue or false, name)
		return property
	end	
	
	cls.WaitChanged = cls.Wait
	
	--- v -> first value
	function cls:WaitEqual(v, ...)
		local vals = {self:GetValue()}
		local extCount = select("#",...)

		if #vals == 1 and extCount == 0 then
			if vals[1] == v then
				return v
			else
				local op = oo.New(WaitSignal, self, function(data) return data == v end)
				return co.yield(op)
				--return self:Wait(function(data) return data == v end)
			end
		else
			local args = {v, ...}
			if TU.ArrayEqual(vals, args) then
				return table.unpack(vals)
			else
				local op = oo.New(WaitSignal, self, function(...) return TU.ArrayEqual({...}, args) end)
				return co.yield(op)
				---return self:Wait(function(...) return TU.ArrayEqual({...}, args) end)
			end
		end
	end
	
	---...要新建一个 WaitProperty 类来实现！！！
	function cls:NewWaitEqual(value)
		if self:GetValue() == value then
			return oo.New(SyncOp, value)
		end
		return self:NewWait(function(data) return data == value end)
	end	
	
	function cls:PropMap(mapper, name)
		return Mapper1.new(self, mapper, name)
	end	
	
	--- 限制: 返回值最终只能返回Property的第一个值. 如果Property有多值(例如TupleProperty), 只能返回第一个.
	function cls:WaitFor(predicate)
		if predicate(self:GetValue()) then 
			return self:GetValue();
		end;
		local op = oo.New(WaitSignal, self, predicate);
		return co.yield(op);
	end

	--- 限制: 返回值最终只能返回Property的第一个值. 如果Property有多值(例如TupleProperty), 只能返回第一个.
	function cls:NewWaitFor(predicate)
		if predicate(self:GetValue()) then 
			return oo.New(SyncOp, self:GetValue());
		end;
		return self:NewWait(predicate);
	end	

	function cls:Tuplize(another, name)
		return TupleProperty.new(self, another, name);
	end
	
	--- 注意: 只对Number类属性有效
	function cls:Inc()
		self:SetValue(self:GetValue() + 1);
	end
	--- 注意: 只对Number类属性有效
	function cls:IncN(n)
		self:SetValue(self:GetValue() + n);
	end
	--- 注意: 只对Number类属性有效
	function cls:Dec()
		self:SetValue(self:GetValue() - 1);
	end
	--- 注意: 只对Number类属性有效
	function cls:DecN(n)
		self:SetValue(self:GetValue() - n);
	end
	--- 将两个Property组合成一个新的Property. 
	--- 这个新的Property的 value 通过mapper对这两个Property映射后得到:
	---  value = mapper(aValue, bValue);
	function cls:Combine(c, mapper, name)
		return Mapper2.new(self, c, mapper, name);
	end	

	--- 取和(加法). 会返回一个新的只读属性(IReadOnlyProperty)
	--- 注意: 只有两个number类Property可以Add, 其它类型会报错!
	function cls:Add(c, name)
		return Mapper2.new(self, c, function(a, b)
			return a + b;
		end, name);
	end		

	--- For boolean property
	--- 取反. 会返回一个新的只读属性(IReadOnlyProperty)
	function cls:Not(name)
		return Mapper1.new(self, function(val)
			return not val;
		end, name);
	end	

	--- 取并. 会返回一个新的只读属性(IReadOnlyProperty)
	function cls:And(c, name)
		return Mapper2.new(self, c, function(a, b)
			return a and b;
		end, name);
	end	

	--- 和 N 个property 取并. 会返回一个新的只读属性(IReadOnlyProperty)
	function cls:AndN(...)
		local mapper = function(...)
			local values = {...};
			local accVal = true;
			for _, val in ipairs(values) do
				accVal = accVal and val;
			end
			return accVal;
		end;
		return MapperN.new(mapper, self, ...);
	end	

	--- 取或. 会返回一个新的只读属性(IReadOnlyProperty)
	function cls:Or(c, name)
		return Mapper2.new(self, c, function(a, b)
			return a or b;
		end, name);
	end	

	--- 和 N 个property 取并. 会返回一个新的只读属性(IReadOnlyProperty)
	function cls:OrN(...)
		local mapper = function(...)
			local values = {...};
			local accVal = true;
			for _, val in ipairs(values) do
				accVal = accVal or val;
			end
			return accVal;
		end;
		return MapperN.new(mapper, self, ...);
	end
	
	--- 取异或. 会返回一个新的只读属性(IReadOnlyProperty)
	function cls:Xor(c, name)
		return Mapper2.new(self, c, function(a, b)
			return a ~= b;
		end, name);
	end
end

return m;
